package cn.studyjams.s1.contest.autohello.service;

import android.app.AlarmManager;
import android.app.IntentService;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.AsyncTask;
import android.preference.PreferenceManager;
import android.support.v4.app.NotificationCompat;
import android.support.v4.content.ContextCompat;
import android.telephony.SmsManager;
import android.util.Log;

import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;

import org.json.JSONException;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import cn.studyjams.s1.contest.autohello.MainActivity;
import cn.studyjams.s1.contest.autohello.R;
import cn.studyjams.s1.contest.autohello.model.Contact;
import cn.studyjams.s1.contest.autohello.model.Event;
import cn.studyjams.s1.contest.autohello.model.RepeatMode;
import cn.studyjams.s1.contest.autohello.model.Weather;
import cn.studyjams.s1.contest.autohello.receiver.NotificationReceiver;
import cn.studyjams.s1.contest.autohello.utils.JSONWeatherParser;
import cn.studyjams.s1.contest.autohello.utils.WeatherHttpClient;

public class AlarmTriggerService extends IntentService {

    private final static String TAG = "AlarmTriggerService";

    public AlarmTriggerService() {
        super("AlarmTriggerService");
    }

    private Event event;
    private Weather mWeather;
    NotificationManager notificationManager;

    DatabaseReference eventRef;

    private List<String> sendSuc = new ArrayList<>();
    private List<String> sendFai = new ArrayList<>();
    // private List<Map<String, Boolean>> sendResult = new ArrayList<>();

    private String SMSContent;
    private List<String> SMSContentList = new ArrayList<>();
    private List<String[]> SMSReceivers = new ArrayList<>();
    private List<String[]> EMAILReceivers = new ArrayList<>();
    private int color = 5;
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault());

    SharedPreferences sharedPref;
    private int[] colors;

    @Override
    protected void onHandleIntent(final Intent intent) {
        sharedPref = PreferenceManager.getDefaultSharedPreferences(this);

        String eventId = intent.getStringExtra("event_id");
        Log.d(TAG, eventId);

        colors = new int[]{
                ContextCompat.getColor(this, R.color.tomato),
                ContextCompat.getColor(this, R.color.banana),
                ContextCompat.getColor(this, R.color.cucumber),
                ContextCompat.getColor(this, R.color.blueBerry),
                ContextCompat.getColor(this, R.color.grape),
                ContextCompat.getColor(this, R.color.defaultColor)
        };

        notificationManager = (NotificationManager) this.getSystemService(
                Context.NOTIFICATION_SERVICE
        );

        FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();

        // 获取event信息，准备发送短信/邮件的内容及联系人
        if (user != null) {
            eventRef = FirebaseDatabase.getInstance().getReference()
                    .child("events")
                    .child(user.getUid())
                    .child(eventId);
            eventRef.addListenerForSingleValueEvent(new ValueEventListener() {
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) {
                    event = dataSnapshot.getValue(Event.class);
                    color = event.getColor();
                    SMSContent = event.getContent();

                    int index = 0;
                    while (index < SMSContent.length()) {
                        SMSContentList.add(
                                SMSContent.substring(
                                        index,
                                        Math.min(index + 160, SMSContent.length())
                                )
                        );
                        index += 160;
                    }

                    for (Contact receiver : event.getReceivers()) {
                        if (receiver.getType() == 0) {
                            // type == 0 : phone
                            SMSReceivers.add(
                                    new String[]{
                                            receiver.getName(),
                                            receiver.getPhoneNumber()
                                    }
                            );
                        } else {
                            // type == 1 : email
                            EMAILReceivers.add(
                                    new String[]{
                                            receiver.getName(),
                                            receiver.getEmailAddress()
                                    }
                            );
                        }
                    }

                    if (event.getType() == 1) {
                        Double lat = event.getLat();
                        Double lon = event.getLon();
                        JSONWeatherTask task = new JSONWeatherTask();
                        task.execute(lat, lon);
                        Log.d(TAG, lat + "/" + lon);

                    } else {
                        // 向 SMSReceivers 中的每个人发送短信
                        for (String[] receiver : SMSReceivers) {
                            sendSMS(receiver);
                        }
                    }

                    updateDataAndSetAlarm();
                    sentNotification();
                }

                @Override
                public void onCancelled(DatabaseError databaseError) {

                    PendingIntent pendingIntent = PendingIntent.getActivity(
                            AlarmTriggerService.this,
                            0,
                            new Intent(AlarmTriggerService.this, MainActivity.class),
                            0
                    );
                    NotificationCompat.Builder builder = new NotificationCompat
                            .Builder(AlarmTriggerService.this)
                            .setSmallIcon(R.mipmap.ic_launcher)
                            .setLargeIcon(
                                    BitmapFactory.decodeResource(
                                            AlarmTriggerService.this.getResources(),
                                            R.mipmap.ic_launcher
                                    )
                            ).setColor(
                                    ContextCompat.getColor(
                                            AlarmTriggerService.this,
                                            R.color.colorAccent
                                    )
                            ).setContentTitle(getString(R.string.noti_read_database_fail))
                            .setContentText(getString(R.string.noti_check_connection))
                            .setContentIntent(pendingIntent)
                            .setAutoCancel(true);

                    setNotifications(builder, true);

                    notificationManager.notify((int) System.currentTimeMillis(), builder.build());
                }
            });

        } else {

            PendingIntent loginPendingIntent = PendingIntent.getActivity(
                    this,
                    0,
                    new Intent(this, MainActivity.class),
                    0
            );

            NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setLargeIcon(
                            BitmapFactory.decodeResource(
                                    AlarmTriggerService.this.getResources(),
                                    R.mipmap.ic_launcher
                            )
                    ).setColor(
                            ContextCompat.getColor(
                                    AlarmTriggerService.this,
                                    R.color.colorAccent
                            )
                    ).setContentTitle(getString(R.string.noti_unlogin))
                    .setContentText(getString(R.string.noti_login_again))
                    .setAutoCancel(true)
                    .setContentIntent(loginPendingIntent);

            setNotifications(builder, true);
            notificationManager.notify((int) System.currentTimeMillis(), builder.build());
        }
    }

    private void sendSMS(String[] receiver) {
        try {

            SmsManager smsMgr = SmsManager.getDefault();
            for (String content : SMSContentList) {
                smsMgr.sendTextMessage(receiver[1], null, content, null, null);
            }
            sendSuc.add(receiver[0]);
        } catch (Exception e) {
            Log.e(TAG, e.toString());
            sendFai.add(receiver[0]);
        }
    }

    private void sendSMS(String[] receiver, String weatherDecode) {
        try {

            SmsManager smsMgr = SmsManager.getDefault();
            for (String content : SMSContentList) {
                content = content.replace(getString(R.string.weather_encode), weatherDecode);
                Log.d(TAG, content);
                smsMgr.sendTextMessage(receiver[1], null, content, null, null);
            }
            sendSuc.add(receiver[0]);
        } catch (Exception e) {
            Log.e(TAG, e.toString());
            sendFai.add(receiver[0]);
        }
    }

    private Calendar getNextExecuteTime(Calendar calendar, RepeatMode repeatMode) {
        int repeatType = repeatMode.getRepeatType();
        int howOften = repeatMode.getHowOften();

        switch (repeatType) {
            case 0:
                // does not repeat
                calendar.add(Calendar.DATE, 1);
                break;
            case 1:
                // repeat daily howOften
                calendar.add(Calendar.DATE, howOften);
                break;
            case 2:
                // repeat weekly howOften, whichWeeks;
                int currentDayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
                String weeksStr = repeatMode.getWhichWeeks();
                String[] whichWeeks = weeksStr.substring(1, weeksStr.length() - 1).split(", ");

                int nextIndex;
                // 明天是不是一个新的星期
                if (currentDayOfWeek < 7) {
                    nextIndex = currentDayOfWeek;
                } else {
                    // currentDayOfWeek == 7
                    nextIndex = 0;
                }

                int plusDays = 1;
                while (whichWeeks[nextIndex].equals("false")) {
                    nextIndex = ++nextIndex % 7;
                    plusDays++;
                }

                calendar.add(Calendar.DATE, (howOften - 1) * 7 + plusDays);
                break;
            case 3:
                // repeat monthly howOften, SameDayOrSameWeekOfTheMonth;
                int sameDayOrSameWeek = repeatMode.getSameDayOrSameWeekOfTheMonth();
                if (sameDayOrSameWeek == 0) {
                    calendar.add(Calendar.MONTH, howOften);
                } else if (sameDayOrSameWeek == 1) {
                    // 获取当前日期是星期几，和是本月的第几个星期几
                    int week = calendar.get(Calendar.DAY_OF_WEEK);
                    int weekIndex = calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH);

                    calendar.add(Calendar.MONTH, howOften);
                    calendar.set(Calendar.DAY_OF_WEEK, week);
                    calendar.set(Calendar.DAY_OF_WEEK_IN_MONTH, weekIndex);
                }
                break;
            case 4:
                // repeat yearly howOften;
                calendar.add(Calendar.YEAR, howOften);
                break;
            default:
                break;
        }
        return calendar;
    }

    private void updateDataAndSetAlarm() {
        //set alarm and update firebase data;
        if (event != null) {
            RepeatMode repeatMode = event.getRepeatMode();
            String dateTimeStr = event.getDateTime();
            Calendar nextExecuteCalendar = Calendar.getInstance();

            try {
                nextExecuteCalendar.setTime(sdf.parse(dateTimeStr));
                nextExecuteCalendar = getNextExecuteTime(nextExecuteCalendar, repeatMode);

                String nextExecuteStr = new SimpleDateFormat(
                        "yyyy-MM-dd HH:mm",
                        Locale.getDefault()
                ).format(nextExecuteCalendar.getTime());

                if (repeatMode.getRepeatType() == 0) {
                    event.setIsActive(false);
                    eventRef.child("isActive").setValue(false);
                } else {
                    switch (repeatMode.getEndCondition()) {
                        case 0:
                            //无限重复, does nothing
                            break;
                        case 1:
                            //截至到某个日期
                            String endDateTime = repeatMode.getEndDateTime();
                            Date endDate = new SimpleDateFormat(
                                    "yyyy-MM-dd HH:mm",
                                    Locale.getDefault()
                            ).parse(endDateTime);

                            Date nextDate = nextExecuteCalendar.getTime();

                            if (nextDate.compareTo(endDate) > 0) {
                                // 下次执行时间在截至时间之后, 故该事件不再执行
                                eventRef.child("isActive").setValue(false);
                                event.setIsActive(false);
                            }
                            break;
                        case 2:
                            //执行一定次数
                            int leftCounts = repeatMode.getEndCounts();
                            if (leftCounts == 1) {
                                eventRef.child("repeatMode")
                                        .child("endCounts").setValue(0);
                                eventRef.child("isActive").setValue(false);
                                event.setIsActive(false);
                            } else {
                                eventRef.child("repeatMode")
                                        .child("endCounts").setValue(--leftCounts);
                            }
                            break;
                        default:
                            break;
                    }
                }

                eventRef.child("dateTime").setValue(nextExecuteStr);

                //设置下一次的闹铃
                AlarmManager alarmMgr = (AlarmManager) getSystemService(ALARM_SERVICE);

                Intent notificationIntent = new Intent(getApplicationContext(), NotificationReceiver.class);
                notificationIntent.putExtra("event_id", event.getId());

                PendingIntent alarmIntent = PendingIntent.getBroadcast(
                        getApplicationContext(),
                        (int) event.getRequestCode(),
                        notificationIntent,
                        PendingIntent.FLAG_UPDATE_CURRENT
                );

                if (event.getIsActive()) {
                    //设置闹铃
                    alarmMgr.set(
                            AlarmManager.RTC,
                            nextExecuteCalendar.getTimeInMillis(),
                            alarmIntent
                    );
                } else {
                    //取消闹铃
                    alarmMgr.cancel(alarmIntent);
                }

            } catch (Exception e) {
                Log.e(TAG, e.toString());
            }
        }
    }

    private void sentNotification() {
        // send notification
        // 发送成功
        if (sendSuc.size() > 0) {
            String title;
            if (sendSuc.size() == 1) {
                title = String.format(
                        getString(R.string.noti_send_suc_single),
                        sendSuc.get(0)
                );
            } else {
                title = String.format(
                        getString(R.string.noti_send_suc_multi),
                        sendSuc.get(0),
                        sendSuc.size() + ""
                );
            }

            // TODO: 2016/12/3 change MainActivity.class to DetailEventActivity
            PendingIntent pendingIntent = PendingIntent.getActivity(
                    AlarmTriggerService.this,
                    0,
                    new Intent(AlarmTriggerService.this, MainActivity.class),
                    0
            );

            NotificationCompat.Builder builderSuc = new NotificationCompat
                    .Builder(AlarmTriggerService.this)
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setLargeIcon(
                            BitmapFactory.decodeResource(
                                    AlarmTriggerService.this.getResources(),
                                    R.mipmap.ic_launcher
                            )
                    ).setColor(colors[color])
                    .setContentTitle(title)
                    .setContentText(SMSContent)
                    .setContentIntent(pendingIntent)
                    .setAutoCancel(true);

            setNotifications(builderSuc, false);
            notificationManager.notify((int) System.currentTimeMillis(), builderSuc.build());
        }

        // 发送失败
        if (sendFai.size() > 0) {

            // TODO: 2016/12/3 change MainActivity.class to DetailEventActivity
            PendingIntent pendingIntent = PendingIntent.getActivity(
                    AlarmTriggerService.this,
                    0,
                    new Intent(AlarmTriggerService.this, MainActivity.class),
                    0
            );

            NotificationCompat.Builder builderFai = new NotificationCompat
                    .Builder(AlarmTriggerService.this)
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setLargeIcon(
                            BitmapFactory.decodeResource(
                                    AlarmTriggerService.this.getResources(),
                                    R.mipmap.ic_launcher
                            )
                    ).setColor(
                            ContextCompat.getColor(
                                    AlarmTriggerService.this,
                                    R.color.colorAccent
                            )
                    )
                    .setContentTitle(
                            String.format(
                                    getString(R.string.noti_send_fai),
                                    sendFai.toString()
                            )
                    ).setContentText(getString(R.string.noti_send_fai_text))
                    .setContentIntent(pendingIntent)
                    .setAutoCancel(true);

            setNotifications(builderFai, true);
            notificationManager.notify((int) System.currentTimeMillis(), builderFai.build());
        }
    }

    private class JSONWeatherTask extends AsyncTask<Double, Void, Weather> {

        @Override
        protected Weather doInBackground(Double... params) {
            Weather weather = new Weather();
            String data = ((new WeatherHttpClient()).getWeatherData(params[0], params[1]));

            try {
                weather = JSONWeatherParser.getWeather(data);

            } catch (JSONException e) {
                e.printStackTrace();
            }
            return weather;
        }

        @Override
        protected void onPostExecute(Weather weather) {
            super.onPostExecute(weather);
            mWeather = weather;

            if (mWeather != null) {
                String condition = mWeather.currentCondition.getCondition();
                String temperature;
                if (event.getIsCF()) {
                    temperature = Math.round((mWeather.temperature.getTemp() - 273.15)) + " C";
                } else {
                    temperature = Math.round((mWeather.temperature.getTemp())) + " F";
                }

                String weatherDecode = String.format(
                        getString(R.string.weather_decode),
                        condition,
                        temperature
                );

                // 向 SMSReceivers 中的每个人发送短信
                for (String[] receiver : SMSReceivers) {
                    Log.d(TAG, "send sms");
                    sendSMS(receiver, weatherDecode);
                }

                updateDataAndSetAlarm();
                sentNotification();
            } else {
                //获取天气失败
                NotificationCompat.Builder builderFai = new NotificationCompat
                        .Builder(AlarmTriggerService.this)
                        .setSmallIcon(R.mipmap.ic_launcher)
                        .setLargeIcon(
                                BitmapFactory.decodeResource(
                                        AlarmTriggerService.this.getResources(),
                                        R.mipmap.ic_launcher
                                )
                        ).setColor(
                                ContextCompat.getColor(
                                        AlarmTriggerService.this,
                                        R.color.colorAccent
                                )
                        )
                        .setContentTitle(getString(R.string.noti_send_fai_text))
                        .setAutoCancel(true);

                setNotifications(builderFai, true);
                notificationManager.notify((int) System.currentTimeMillis(), builderFai.build());
            }
        }
    }

    private void setNotifications(NotificationCompat.Builder builder, boolean isError) {
        if (sharedPref.getBoolean("notifications_new_message", true)) {
            if (sharedPref.getBoolean("notifications_new_message_vibrate", true)) {
                if (isError) {
                    builder.setVibrate(new long[]{0, 500, 500, 500});
                } else {
                    builder.setVibrate(new long[]{0, 500});
                }
            }

            String soundStr = sharedPref.getString(
                    "notifications_new_message_ringtone",
                    "DEFAULT_SOUND"
            );

            Uri soundUri = Uri.parse(soundStr);
            builder.setSound(soundUri);
        }
    }
}